package com.yxplearn.mybatisplus.collision;

import javax.swing.*;
import java.awt.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

public class BallSecond {

    private static final ScheduledExecutorService scheduledExecutorService = Executors.newSingleThreadScheduledExecutor();
    private static final List<BallS> balls = new ArrayList<>();
    private static int width = 800;
    private static int hight = 600;
    private static MyRectangle myRectangle = new MyRectangle(250, 250, 300, 300);

    public static void main(String[] args) {
        JFrame win = new JFrame();//新建窗口
        win.setLocation(250, 100);//设置窗口位置
        win.setSize(width, hight);//设置窗口大小
        win.setVisible(true);//显示窗口
        win.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);//设置关闭退出
        for (int i = 0; i < 2; i++) {
            BallS ball = new BallS(width, hight);
            balls.add(ball);
        }
        MyJPanel myJPanel = new MyJPanel();
        win.add(myJPanel);
        start(myJPanel);
    }

    static class MyJPanel extends JPanel {

        public void paint(Graphics g) {
            g.clearRect(0, 0, width, hight);
            Rectangle rectangle1 = new Rectangle(0, 0, 2, 2);
            balls.forEach(e -> {
                g.setColor(e.color);
                g.fillOval((int) e.x, (int) e.y, 2 * (int) e.r, 2 * (int) e.r);
            });
            g.drawRect((int) myRectangle.x, (int) myRectangle.y, (int) myRectangle.width, (int) myRectangle.height);
        }
    }

    public static void start(MyJPanel myJPanel) {
        scheduledExecutorService.scheduleAtFixedRate(() -> {
            moveBall(myJPanel);
            myJPanel.repaint();
        }, 20, 5, TimeUnit.MILLISECONDS);
    }

    //让小球移动
    public static void moveBall(MyJPanel myJPanel) {
        for (int i = 0; i < balls.size(); i++) {
            balls.get(i).move(width, hight, myRectangle);
            myJPanel.repaint();
            //移动后检测小球碰撞反弹
            for (int j = 0; j < balls.size(); j++) {
                //判断不是同一个球
                if (balls.get(i) == balls.get(j)) {
                    continue;//不做碰撞检测
                }
                //碰撞检测
                if (ballCrash(balls.get(i), balls.get(j))) {

                    /*
                     1.物理公式动量守恒，假设每个球的质地均匀，那么小球的质量与半径有关
                     2.我们用1一次方的算法，实际平面球质量和r的平方有关，立体球和r的三次方有关
                     3.由动量守恒，m1*v1+m2*v2=m1*v1'+m2*v2'
                     4.机械能守恒，平方我就不写了，两个方程联立
                     */

                    double fzx = DoubleUtl.sum(DoubleUtl.mul(DoubleUtl.sub(balls.get(i).r, balls.get(j).r), balls.get(i).speedX), 2 * DoubleUtl.mul(balls.get(j).r, balls.get(j).speedX));
//                    double fzx = (balls.get(i).r - balls.get(j).r) * balls.get(i).speedX + 2 * balls.get(j).r * balls.get(j).speedX;
//                    double fzx2 = DoubleUtl.sum(2 * DoubleUtl.mul(balls.get(i).r, balls.get(i).speedX) , DoubleUtl.(balls.get(i).r - balls.get(j).r) * balls.get(j).speedX;
                    double fzx2 = 2 * balls.get(i).r * balls.get(i).speedX + (balls.get(i).r - balls.get(j).r) * balls.get(j).speedX;
                    double fzy = (balls.get(i).r - balls.get(j).r) * balls.get(i).speedY + 2 * balls.get(j).r * balls.get(j).speedY;
                    double fzy2 = 2 * balls.get(i).r * balls.get(i).speedY + (balls.get(i).r - balls.get(j).r) * balls.get(j).speedY;
                    double fm = balls.get(i).r + balls.get(j).r;

                    balls.get(i).speedX = (fzx / fm) != 0 ? (fzx / fm) : 1;
                    balls.get(i).speedY = (fzy / fm) != 0 ? (fzy / fm) : 1;
                    balls.get(j).speedX = (fzx2 / fm) != 0 ? (fzx2 / fm) : 1;
                    balls.get(j).speedY = (fzy2 / fm) != 0 ? (fzy2 / fm) : 1;
//                    balls.get(i).speedX = new BigDecimal(fzx).divide(new BigDecimal(fm)).doubleValue();
//                    balls.get(i).speedY = new BigDecimal(fzy).divide(new BigDecimal(fm)).doubleValue();
//                    balls.get(j).speedX = new BigDecimal(fzx2).divide(new BigDecimal(fm)).doubleValue();
//                    balls.get(j).speedY = new BigDecimal(fzy2).divide(new BigDecimal(fm)).doubleValue();
                    if (balls.get(i).speedX == 0) {
                        System.out.println(balls.get(i));
                    }
                }
            }
        }
    }


    //碰撞检测
    public static boolean ballCrash(BallS ball1, BallS ball2) {

        //两个小球之间的距离
        double distance = Math.sqrt(Math.pow(ball1.f - ball2.f, 2) + Math.pow(ball1.m - ball2.m, 2));
        //两球的距离小于两个半径的和即为碰撞
        if (distance == ball1.r + ball2.r) {

            return true;//碰撞
        } else if (distance < ball1.r + ball2.r) {
            if (Math.pow(ball1.speedX, 2) + Math.pow(ball1.speedY, 2) > Math.pow(ball2.speedX, 2) + Math.pow(ball2.speedY, 2)) {
                if (ball1.speedX > 0) {
                    ball1.f = ball1.f + ball1.r + ball2.r - distance;
                    if (ball1.speedY > 0) {
                        ball2.m = ball2.m + ball1.r + ball2.r - distance;
                    } else {
                        ball2.m = ball2.m - ball1.r - ball2.r + distance;
                    }
                } else {
                    ball1.f = ball1.f - ball1.r - ball2.r + distance;
                    if (ball1.speedY > 0) {
                        ball2.m = ball2.m + ball1.r + ball2.r - distance;
                    } else {
                        ball2.m = ball2.m - ball1.r - ball2.r + distance;
                    }
                }

            } else {
                if (ball2.speedX > 0) {
                    ball1.f = ball1.f + ball1.r + ball2.r - distance;
                    if (ball2.speedY > 0) {
                        ball1.m = ball1.m + ball1.r + ball2.r - distance;
                    } else {
                        ball1.m = ball1.m - ball1.r - ball2.r + distance;
                    }
                } else {
                    ball1.f = ball1.f - ball1.r - ball2.r + distance;
                    if (ball2.speedY > 0) {
                        ball1.m = ball1.m + ball1.r + ball2.r - distance;
                    } else {
                        ball1.m = ball1.m - ball1.r - ball2.r + distance;
                    }
                }
            }
            return true;
        } else {
            return false;//没有碰撞
        }
    }

}
